package game.resources;

import game.resources.TikalPlayer.TikalAction;
import game.structures.Point;

public class Angle {
	
	interface AngleType {
        float getAngle(Point point, float angle, Point direction);
    }

    private static AngleType[] angleTypes = new AngleType[] {
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfEmpty(angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfBox(angle, direction); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfBox(angle, direction); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfBox(angle, direction); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfBox(angle, direction); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfBox(angle, direction); } },
        
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOf30DegreeSlope(angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOf30DegreeSlope(angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOf45DegreeSlope(angle); } },
        
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIIICircle1(point, angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIIICircle2(point, angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIIICircle3(point, angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIinnerCircle1(point, angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIinnerCircle2(point, angle); } },
        new AngleType() { public float getAngle(Point point, float angle, Point direction) { return getAngleOfQuadIinnerCircle3(point, angle); } },
        
    };
	
	public static float getTileAngle(int id, Point point, float angle, Point direction) {
		return angleTypes[id].getAngle(point, angle, direction);
	}
	
	private static float getAngleOfEmpty(float angle) {
		return angle;
	}
	
	private static float getAngleOfBox(float angle, Point direction) {
		//System.out.println(direction);
		if 		(direction.getY() > direction.getX()) 
			if 	(direction.getY() > -direction.getX())
				return 0.0f;
			else
				return 90.0f;
		else if (direction.getY() < direction.getY())
			if 	(direction.getY() > -direction.getX())
				return 270.0f;
			else
				return 180.0f;
		else return angle;
	}
	
	private static float getAngleOf30DegreeSlope(float angle) {
		if (angle < 75f || angle >= 345f) 
			return 30.0f;
		else if (angle < 135.0f)
			return 90.0f;
		else if (angle < 225.0f)
			return 180.0f;
		else {
			return 270.0f;
		}
	}
	
	private static float getAngleOf45DegreeSlope(float angle) {
		if (angle <= 135.0f || angle >= 315f) 
			return 45.0f;
		else if (angle < 225.0f)
			return 180.0f;
		else {
			return 270.0f;
		}
	}

	private static float getAngleOfQuadIIICircle1(Point point, float angle) {
			if (angle < 45.0f || angle >= 225.0f) {
				Point p = new Point (	-256.0f + point.getX() % 128.0f, 
										point.getY() % 128.0f);
				float x = getAngle(new Point(0.0f, 1.0f), p);
				return 360.0f - x;
			}
			else if (angle < 135)
				return 90.0f;
			else
				return 180.0f;
	}
	private static float getAngleOfQuadIIICircle2(Point point, float angle) {
			if (angle < 45.0f || angle >= 225.0f) {
				Point p = new Point (	-256.0f + point.getX()%128.0f, 
										point.getY()%128.0f + 128.0f);
				float x = getAngle(new Point(0.0f, 1.0f), p);
				return 360.0f - x;
			}
			else if (angle < 135)
				return 90.0f;
			else
				return 180.0f;
	}
	private static float getAngleOfQuadIIICircle3(Point point, float angle) {
			if (angle < 45.0f || angle >= 225.0f) {
				Point p = new Point (	-256.0f + (point.getX()%128.0f + 128.0f), 
										point.getY()%128.0f + 128.0f);
				float x = getAngle(new Point(0.0f, 1.0f), p);
				return 360.0f - x;
			}
			else if (angle < 135)
				return 90.0f;
			else
				return 180.0f;
	}
		
	private static float getAngleOfQuadIinnerCircle1(Point point, float angle) {
		if (angle < 45.0f || angle >= 225.0f) {
			Point p = new Point (	point.getX()%128.0f, 
									256.0f - (point.getY()%128.0f));
			
			float x = getAngle(new Point(0.0f, 1.0f), p);
			return 360.0f - x;
		}
		else if (angle < 135)
			return 90.0f;
		else
			return 180.0f;
	}
	private static float getAngleOfQuadIinnerCircle2(Point point, float angle) {
		if (angle < 45.0f || angle >= 225.0f) {
			Point p = new Point (	point.getX()%128.0f + 128.0f, 
									256.0f - (point.getY() % 128.0f));
			float x = getAngle(new Point(0.0f, 1.0f), p);
			return 360.0f - x;
		}
		else if (angle < 135)
			return 90.0f;
		else
			return 180.0f;
	}
	private static float getAngleOfQuadIinnerCircle3(Point point, float angle) {
		if (angle < 45.0f || angle >= 225.0f) {
			Point p = new Point (	point.getX()%128.0f + 128.0f, 
									256.0f - (point.getY()%128.0f + 128.0f));
			System.out.println(p);
			float x = getAngle(new Point(0.0f, 1.0f), p);
			return 360.0f - x;
		}
		else if (angle < 135)
			return 90.0f;
		else
			return 180.0f;
	}
	
	public static float getAngle(Point a, Point b) {
		//Normalize vectors
		float magnitudeA = (float) Math.sqrt(Math.pow(a.getX(), 2) + Math.pow(a.getY(), 2));
		a = new Point(a.getX()/magnitudeA, a.getY()/magnitudeA);
		
		float magnitudeB = (float) Math.sqrt( Math.pow(b.getX(), 2) + Math.pow(b.getY(), 2));
		b = new Point(b.getX()/magnitudeB, b.getY()/magnitudeB);

		return ((float) Math.acos(	(a.getX() * b.getX() + 
							 a.getY() * b.getY())/
							(Math.sqrt( Math.pow(a.getX(), 2) + Math.pow(a.getY(), 2)) *
							 Math.sqrt( Math.pow(b.getX(), 2) + Math.pow(b.getY(), 2))))) * 180f / (float) Math.PI;
	}

}
